
#ifndef  X_LOGSTREAM_H_
#define  X_LOGSTREAM_H_

#include <cstring>
#include <string>
#include <vector>
using std::string;
using std::vector;

namespace x_log
{

//禁止拷贝/复制基类
class noncopyable
{
protected:
    noncopyable(){}
    ~noncopyable()= default;
public:
    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable&) = delete;
}; //noncopyable

const int kSmallBuffer = 4096;
const int kLargeBuffer = 900 * 1024;  //900KB

template<int SIZE>
class CVecFixedBuffer : noncopyable
{
public:
    CVecFixedBuffer() : m_pcur(nullptr)
    {
        m_data.reserve(SIZE);
        m_pcur = &m_data[0];
    }
    ~CVecFixedBuffer() = default;
    void append(const char* buf, size_t len)
    {
        if (static_cast<size_t>(avail()) > len)
        {
            memcpy(m_pcur, buf, len);
            m_pcur += len;
        }
    }
    const char* data() const { return &m_data[0]; }
    int length()const { return static_cast<int>(m_pcur - &m_data[0]); }
    char* current(){ return m_pcur; }
    int avail(){ return static_cast<int>(end() - m_pcur); }
    void add(size_t len) { m_pcur += len;}
    void reset() { m_pcur = &m_data[0]; }
    void bzero() { m_data.clear(); }
private:
    const char* end() const { return &m_data[m_data.capacity()]; }
    std::vector<char> m_data;
    char* m_pcur;
}; //CVecFixedBuffer

class CLogStream : noncopyable
{
    typedef CLogStream self;
public:
    typedef x_log::CVecFixedBuffer<x_log::kLargeBuffer> Buffer;
    using ftr_new_line = std::ostream& (*)(std::ostream&);
    self& operator<< (bool value)
    {
        m_buffer.append(value ? "1" : "0", 1);
        return *this;
    }
    self& operator<< (short);
    self& operator<< (unsigned short);
    self& operator<< (int);
    self& operator<< (unsigned int);
    self& operator<< (long);
    self& operator<< (unsigned long);
    self& operator<< (long long);
    self& operator<< (unsigned long long);
    self& operator<< (const void*);
    self& operator<< (float value)
    {
        *this << static_cast<double>(value);
        return *this;
    }
    self& operator<< (double);
    self& operator<< (char value)
    {
        m_buffer.append(&value, 1);
        return *this;
    }
    self& operator<< (const char* str)
    {
        if (nullptr != str)
        {
            m_buffer.append(str, strlen(str));
        }
        else
        {
            m_buffer.append("(null)", 6);
        }
        return *this;
    }
    self& operator<< (const unsigned char* str)
    {
        return operator<< (reinterpret_cast<const char*>(str));
    }
    self& operator<< (const std::string& sstring)
    {
        m_buffer.append(sstring.c_str(), sstring.size());
        return *this;
    }
    self& operator<< (ftr_new_line)
    {
        return operator<< ("\n");
    }
    void append(const char* data, size_t len) { m_buffer.append(data, len); }
    const Buffer& buffer() const { return m_buffer; }
    void resetBuffer() { m_buffer.reset(); }
private:
    template<typename T>
    void formatInteger(T);
    Buffer m_buffer;
    static const int kMaxNumericSize = 32;
}; //class CLogStream
} //end namespace x_log

#endif //X_LOGSTREAM_H_

